home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / osrc.arc / FTPCLI.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-05-30  |  17.3 KB  |  763 lines

  1. /* FTP client (interactive user) code */
  2. #include <stdio.h>
  3. #include "global.h"
  4. #include "mbuf.h"
  5. #include "session.h"
  6. #include "cmdparse.h"
  7. #include "timer.h"
  8. #include "proc.h"
  9. #include "tty.h"
  10. #include "socket.h"
  11. #include "ftp.h"
  12. #include "ftpcli.h"
  13.  
  14. #if    defined(__STDC__) || defined(__TURBOC__)
  15. static int dotype(int argc,char *argv[],struct session *sp);
  16. static int getsub(struct ftpcli *ftp,char *command,char *remotename,
  17.     char *localname);
  18. static void sendport(int s,struct sockaddr_in *socket);
  19. #else
  20. static int dotype(),getsub();
  21. static void sendport();
  22. #endif
  23.  
  24. static int donothing(),doftpcd(),dolist(),doget(),dols(),doput(),
  25.     domkdir(),dormdir(),doascii(),dobinary(),doquit();
  26.  
  27. extern char Nospace[],Badhost[];
  28. static char Notsess[] = "Not an FTP session!\n";
  29.  
  30. struct cmds Ftpcmds[] = {
  31.     "",        donothing,    0, 0, NULLCHAR,
  32.     "ascii",    doascii,    0, 0, NULLCHAR,
  33.     "binary",    dobinary,    0, 0, NULLCHAR,
  34.     "cd",        doftpcd,    0, 2, "cd <directory>",
  35.     "dir",        dolist,        0, 0, NULLCHAR,
  36.     "list",        dolist,        0, 0, NULLCHAR,
  37.     "get",        doget,        0, 2, "get remotefile <localfile>",
  38.     "ls",        dols,        0, 0, NULLCHAR,
  39.     "mkdir",    domkdir,    0, 2, "mkdir <directory>",
  40.     "nlst",        dols,        0, 0, NULLCHAR,
  41.     "quit",        doquit,        0, 0, NULLCHAR,
  42.     "rmdir",    dormdir,    0, 2, "rmdir <directory>",
  43.     "put",        doput,        0, 2, "put localfile <remotefile>",
  44.     "type",        dotype,        0, 0, NULLCHAR,
  45.     NULLCHAR,    NULLFP,        0, 0, NULLCHAR,
  46. };
  47.  
  48. /* Handle top-level FTP command */
  49. doftp(argc,argv)
  50. int argc;
  51. char *argv[];
  52. {
  53.     struct session *sp;
  54.     struct ftpcli ftp;
  55.     struct sockaddr_in fsocket;
  56.     int resp;
  57.     struct mbuf *bp,*bpsav;
  58.     char *cp;
  59.     int control;
  60.  
  61.     /* Allocate a session control block */
  62.     if((sp = newsession(argv[1],FTP)) == NULLSESSION){
  63.         printf("Too many sessions\n");
  64.         return 1;
  65.     }
  66.     memset((char *)&ftp,0,sizeof(ftp));
  67.     ftp.control = ftp.data = -1;
  68.  
  69.     sp->cb.ftp = &ftp;    /* Downward link */
  70.     ftp.session = sp;    /* Upward link */
  71.     ftp.output = Curproc;
  72.  
  73.     fsocket.sin_family = AF_INET;
  74.     if(argc < 3)
  75.         fsocket.sin_port = IPPORT_FTP;
  76.     else
  77.         fsocket.sin_port = atoi(argv[2]);
  78.  
  79.     Current = sp;
  80.     Mode = CONV_MODE;
  81.     if((fsocket.sin_addr.s_addr = resolve(sp->name)) == 0){
  82.         printf(Badhost,sp->name);
  83.         freesession(sp);
  84.         return 1;
  85.     }
  86.     /* Open the control connection */
  87.     if((control = sp->s = ftp.control = socket(AF_INET,SOCK_STREAM,0)) == -1){
  88.         printf("Can't create socket\n");
  89.         freesession(sp);
  90.         return 1;
  91.     }
  92.     printf("Trying %s...\n",psocket((struct sockaddr *)&fsocket));
  93.     if(connect(control,(char *)&fsocket,sizeof(fsocket)) == -1)
  94.         goto quit;
  95.     printf("FTP session %u connected to %s\n",(unsigned)(sp-Sessions),
  96.         sp->name);
  97.  
  98.     /* Wait for greeting from server */
  99.     resp = getresp(control,200);
  100.  
  101.     /* Now process responses and commands */
  102.     for(;;){
  103.         switch(resp){
  104.         case -1:
  105.             goto quit;
  106.         case 220: /* Sign-on banner; prompt for and send USER command */
  107.             bp = qdata("USER ",5);
  108.             append(&bp,getline(sp,"Enter user name: "));
  109.             if(send_mbuf(control,bp,0,NULLCHAR,0) == -1)
  110.                 goto quit;
  111.             resp = getresp(control,200);
  112.             break;
  113.         case 331: /* Password prompt; get password */
  114.             ttysetmode(TTY_EDIT);    /* turn off echo */
  115.             bp = qdata("PASS ",5);
  116.             append(&bp,getline(sp,"Password: "));
  117.             printf("\r\n");
  118.             if(send_mbuf(control,bp,0,NULLCHAR,0) == -1)
  119.                 goto quit;
  120.             ttysetmode(TTY_EDIT|TTY_ECHO);
  121.             resp = getresp(control,200);
  122.             break;
  123.         default:
  124.             /* Test the control channel first */
  125.             if(sockstate(control) == NULLCHAR)
  126.                 goto quit;
  127.  
  128.             bp = getline(sp,"ftp> ");
  129.  
  130.             /* Copy because cmdparse modifies the original */
  131.             bpsav = copy_p(bp,len_mbuf(bp));
  132.             if((resp = cmdparse(Ftpcmds,bp->data,sp)) != -1){
  133.                 /* Valid command, free buffer and get another */
  134.                 free_p(bpsav);
  135.             } else {
  136.                 /* Not a local cmd, send to remote server */
  137.                 if(send_mbuf(control,bpsav,0,NULLCHAR,0) == -1){
  138.                     free_p(bp);
  139.                     goto quit;
  140.                 }
  141.                 resp = getresp(control,200);
  142.             }
  143.             free_p(bp);
  144.             break;
  145.         }
  146.     }
  147. quit:    cp = sockerr(control);
  148.     printf("FTP session %u closed: %s\n",(unsigned)(sp - Sessions),
  149.      cp != NULLCHAR ? cp : "EOF");
  150.  
  151.     if(ftp.fp != NULLFILE && ftp.fp != stdout)
  152.         fclose(ftp.fp);
  153.     if(ftp.data != -1)
  154.         close_s(ftp.data);
  155.     if(ftp.control != -1)
  156.         close_s(ftp.control);
  157.     if(ftp.session != NULLSESSION)
  158.         freesession(ftp.session);
  159.     return 0;
  160. }
  161.  
  162. /* Handle null line to avoid trapping on first command in table */
  163. static
  164. int
  165. donothing(argc,argv,envp)
  166. int argc;
  167. char *argv[];
  168. void *envp;
  169. {
  170. }
  171. /* Close session */
  172. static int
  173. doquit(argc,argv,sp)
  174. int argc;
  175. char *argv[];
  176. struct session *sp;
  177. {
  178.     register struct ftpcli *ftp;
  179.     int control;
  180.  
  181.     if(sp == NULLSESSION)
  182.         return -1;
  183.     ftp = sp->cb.ftp;
  184.     control = ftp->control;
  185.     usprintf(control,"QUIT\r\n");
  186.     getresp(control,200);    /* Get the closing message */
  187.     getresp(control,200);    /* Wait for the server to close */
  188.     return -1;
  189. }
  190.  
  191. /* Translate 'cd' to 'cwd' for convenience */
  192. static
  193. int
  194. doftpcd(argc,argv,sp)
  195. int argc;
  196. char *argv[];
  197. struct session *sp;
  198. {
  199.     register struct ftpcli *ftp;
  200.  
  201.     if(sp == NULLSESSION)
  202.         return -1;
  203.     ftp = sp->cb.ftp;
  204.     usprintf(ftp->control,"CWD %s\r\n",argv[1]);
  205.     return getresp(ftp->control,200);
  206. }
  207. /* Translate 'mkdir' to 'xmkd' for convenience */
  208. static
  209. int
  210. domkdir(argc,argv,sp)
  211. int argc;
  212. char *argv[];
  213. struct session *sp;
  214. {
  215.     register struct ftpcli *ftp;
  216.  
  217.     if(sp == NULLSESSION)
  218.         return -1;
  219.     ftp = sp->cb.ftp;
  220.     usprintf(ftp->control,"XMKD %s\r\n",argv[1]);
  221.     return getresp(ftp->control,200);
  222. }
  223. /* Translate 'rmdir' to 'xrmd' for convenience */
  224. static
  225. int
  226. dormdir(argc,argv,sp)
  227. int argc;
  228. char *argv[];
  229. struct session *sp;
  230. {
  231.     register struct ftpcli *ftp;
  232.  
  233.     if(sp == NULLSESSION)
  234.         return -1;
  235.     ftp = sp->cb.ftp;
  236.     usprintf(ftp->control,"XRMD %s\r\n",argv[1]);
  237.     return getresp(ftp->control,200);
  238. }
  239. static int
  240. dobinary(argc,argv,sp)
  241. int argc;
  242. char *argv[];
  243. struct session *sp;
  244. {
  245.     char *args[2];
  246.  
  247.     args[1] = "I";
  248.     return dotype(2,args,sp);
  249. }
  250. static int
  251. doascii(argc,argv,sp)
  252. int argc;
  253. char *argv[];
  254. struct session *sp;
  255. {
  256.     char *args[2];
  257.  
  258.     args[1] = "A";
  259.     return dotype(2,args,sp);
  260. }
  261.  
  262. /* Handle "type" command from user */
  263. static
  264. int
  265. dotype(argc,argv,sp)
  266. int argc;
  267. char *argv[];
  268. struct session *sp;
  269. {
  270.     register struct ftpcli *ftp;
  271.     int control;
  272.  
  273.     if(sp == NULLSESSION)
  274.         return -1;
  275.     ftp = sp->cb.ftp;
  276.     control = ftp->control;
  277.     if(argc < 2){
  278.         switch(ftp->type){
  279.         case IMAGE_TYPE:
  280.             printf("Image\n");
  281.             break;
  282.         case ASCII_TYPE:
  283.             printf("Ascii\n");
  284.             break;
  285.         case LOGICAL_TYPE:
  286.             printf("Logical bytesize %u\n",ftp->logbsize);
  287.             break;
  288.         }
  289.         return 0;
  290.     }
  291.     switch(*argv[1]){
  292.     case 'i':
  293.     case 'I':
  294.     case 'b':
  295.     case 'B':
  296.         ftp->typesent = ftp->type = IMAGE_TYPE;
  297.         usprintf(control,"TYPE I\r\n");
  298.         break;
  299.     case 'a':
  300.     case 'A':
  301.         ftp->typesent = ftp->type = ASCII_TYPE;
  302.         usprintf(control,"TYPE A\r\n");
  303.         break;
  304.     case 'L':
  305.     case 'l':
  306.         ftp->typesent = ftp->type = LOGICAL_TYPE;
  307.         ftp->logbsize = atoi(argv[2]);
  308.         usprintf(control,"TYPE L %s\r\n",argv[2]);
  309.         break;
  310.     default:
  311.         printf("Invalid type %s\n",argv[1]);
  312.         return 1;
  313.     }
  314.     return getresp(control,200);
  315. }
  316. /* Start receive transfer. Syntax: get <remote name> [<local name>] */
  317. static
  318. doget(argc,argv,sp)
  319. int argc;
  320. char *argv[];
  321. struct session *sp;
  322. {
  323.     char *remotename,*localname;
  324.     register struct ftpcli *ftp;
  325.  
  326.     if(sp == NULLSESSION)
  327.         return -1;
  328.     ftp = sp->cb.ftp;
  329.     if(ftp == NULLFTP){
  330.         printf(Notsess);
  331.         return 1;
  332.     }
  333.     remotename = argv[1];
  334.     if(argc < 3)
  335.         localname = remotename;
  336.     else
  337.         localname = argv[2];
  338.  
  339.     return getsub(ftp,"RETR",remotename,localname);
  340. }
  341. /* List remote directory. Syntax: dir <remote files> [<local name>] */
  342. static
  343. dolist(argc,argv,sp)
  344. int argc;
  345. char *argv[];
  346. struct session *sp;
  347. {
  348.     char *remotename,*localname;
  349.     register struct ftpcli *ftp;
  350.  
  351.     if(sp == NULLSESSION)
  352.         return -1;
  353.     ftp = sp->cb.ftp;
  354.     if(ftp == NULLFTP){
  355.         printf(Notsess);
  356.         return 1;
  357.     }
  358.     remotename = argv[1];
  359.     if(argc > 2)
  360.         localname = argv[2];
  361.     else
  362.         localname = NULLCHAR;
  363.     return getsub(ftp,"LIST",remotename,localname);
  364. }
  365. /* Remote directory list, short form. Syntax: ls <remote files> [<local name>] */
  366. static
  367. dols(argc,argv,sp)
  368. int argc;
  369. char *argv[];
  370. struct session *sp;
  371. {
  372.     char *remotename,*localname;
  373.     register struct ftpcli *ftp;
  374.  
  375.     if(sp == NULLSESSION)
  376.         return -1;
  377.     ftp = sp->cb.ftp;
  378.     if(ftp == NULLFTP){
  379.         printf(Notsess);
  380.         return 1;
  381.     }
  382.     remotename = argv[1];
  383.     if(argc > 2)
  384.         localname = argv[2];
  385.     else
  386.         localname = NULLCHAR;
  387.     return getsub(ftp,"NLST",remotename,localname);
  388. }
  389. /* Common code to LIST/NLST/RETR */
  390. static int
  391. getsub(ftp,command,remotename,localname)
  392. struct ftpcli *ftp;
  393. char *command,*remotename,*localname;
  394. {
  395.     unsigned long total;
  396.     FILE *fp;
  397.     int cnt,resp,i,control;
  398.     char *mode;
  399.     struct sockaddr_in lsocket;
  400.     int32 startclk,rate;
  401.  
  402.     if(ftp == NULLFTP)
  403.         return -1;
  404.     control = ftp->control;
  405.  
  406.     switch(ftp->type){
  407.     case IMAGE_TYPE:
  408.     case LOGICAL_TYPE:
  409.         mode = WRITE_BINARY;
  410.         break;
  411.     case ASCII_TYPE:
  412.         mode = WRITE_TEXT;
  413.         break;
  414.     }
  415.     /* Send TYPE message, if necessary */
  416.     if(strcmp(command,"LIST") == 0 || strcmp(command,"NLST") == 0){
  417.         if(ftp->typesent != ASCII_TYPE){
  418.             /* Directory listings are always in ASCII */
  419.             usprintf(control,"TYPE A\r\n");
  420.             ftp->typesent = ASCII_TYPE;
  421.             resp = getresp(control,200);
  422.             if(resp == -1 || resp > 299){
  423.                 return 1;
  424.             }
  425.         }
  426.     } else if(ftp->typesent != ftp->type){
  427.         switch(ftp->type){
  428.         case ASCII_TYPE:
  429.             usprintf(control,"TYPE A\r\n");
  430.             break;
  431.         case IMAGE_TYPE:
  432.             usprintf(control,"TYPE I\r\n");
  433.             break;
  434.         case LOGICAL_TYPE:
  435.             usprintf(control,"TYPE L %d\r\n",ftp->logbsize);
  436.             break;
  437.         }
  438.         ftp->typesent = ftp->type;
  439.         resp = getresp(control,200);
  440.         if(resp == -1 || resp > 299){
  441.             return 1;
  442.         }
  443.     }
  444.     if(localname == NULLCHAR){
  445.         fp = stdout;
  446.     } else if((fp = fopen(localname,mode)) == NULLFILE){
  447.         printf("Can't write %s: %s\n",localname,sys_errlist[errno]);
  448.         return 1;
  449.     }
  450.     /* Open the data connection */
  451.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  452.     listen(ftp->data,0);    /* Accept only one connection */
  453.     ftp->state = RECEIVING_STATE;
  454.  
  455.     /* Send the PORT message and wait for ack */
  456.     i = SOCKSIZE;
  457.     getsockname(ftp->data,(char *)&lsocket,&i);
  458.     sendport(control,&lsocket);
  459.     resp = getresp(control,200);
  460.     if(resp == -1 || resp > 299){
  461.         /* Error, quit */
  462.         if(fp != stdout)
  463.             fclose(fp);
  464.         close_s(ftp->data);
  465.         ftp->data = -1;
  466.         ftp->state = COMMAND_STATE;
  467.         return 1;
  468.     }
  469.     /* Generate the command to start the transfer and wait for ack */
  470.     if(remotename != NULLCHAR)
  471.         usprintf(control,"%s %s\r\n",command,remotename);
  472.     else
  473.         usprintf(control,"%s\r\n",command);
  474.     /* Get the intermediate "150" response */
  475.     resp = getresp(control,100);
  476.     if(resp == -1 || resp >= 400){
  477.         /* Error, quit */
  478.         if(fp != stdout)
  479.             fclose(fp);
  480.         close_s(ftp->data);
  481.         ftp->data = -1;
  482.         ftp->state = COMMAND_STATE;
  483.         return 1;
  484.     }
  485.     /* Wait for the server to open the data connection */
  486.     cnt = 0;
  487.     ftp->data = accept(ftp->data,NULLCHAR,&cnt);
  488.     startclk = Clock;
  489.  
  490.     total = recvfile(fp,ftp->data,ftp->type);
  491.     /* Immediately close the data connection; some servers (e.g., TOPS-10)
  492.      * wait for the data connection to close completely before returning
  493.      * the completion message on the control channel
  494.      */
  495.     close_s(ftp->data);
  496.     ftp->data = -1;
  497.  
  498. #ifdef    CPM
  499.     if(ftp->type == ASCII_TYPE)
  500.         fputc(CTLZ,fp);
  501. #endif
  502.     if(fp != stdout)
  503.         fclose(fp);
  504.     startclk = Clock - startclk;
  505.     if(startclk != 0)
  506.         rate = total/startclk;
  507.     else
  508.         rate = 0;
  509.     if(total != -1)
  510.         printf("Get complete: %lu bytes in %lu sec (%lu/sec)\n",
  511.          total,(startclk*MSPTICK)/1000,(rate*1000)/MSPTICK);
  512.     else
  513.         printf("Error or abort during data transfer\n");
  514.     getresp(control,200);
  515.  
  516.     ftp->state = COMMAND_STATE;
  517.     return 0;
  518. }
  519. /* Send a file. Syntax: put <local name> [<remote name>] */
  520. static
  521. doput(argc,argv,sp)
  522. int argc;
  523. char *argv[];
  524. struct session *sp;
  525. {
  526.     char *remotename,*localname,*mode;
  527.     register struct ftpcli *ftp;
  528.     int i,resp,control;
  529.     unsigned long total;
  530.     FILE *fp;
  531.     struct sockaddr_in lsocket;
  532.     int32 startclk,rate;
  533.  
  534.     if(sp == NULLSESSION)
  535.         return -1;
  536.     ftp = sp->cb.ftp;
  537.     control = ftp->control;
  538.  
  539.     if(ftp == NULLFTP){
  540.         printf(Notsess);
  541.         return 1;
  542.     }
  543.     localname = argv[1];
  544.     if(argc < 3)
  545.         remotename = localname;
  546.     else
  547.         remotename = argv[2];
  548.  
  549.     if(ftp->type == IMAGE_TYPE)
  550.         mode = READ_BINARY;
  551.     else
  552.         mode = READ_TEXT;
  553.  
  554.     /* Send TYPE message, if necessary */
  555.     if(ftp->typesent != ftp->type){
  556.         switch(ftp->type){
  557.         case ASCII_TYPE:
  558.             usprintf(control,"TYPE A\r\n");
  559.             break;
  560.         case IMAGE_TYPE:
  561.             usprintf(control,"TYPE I\r\n");
  562.             break;
  563.         case LOGICAL_TYPE:
  564.             usprintf(control,"TYPE L %d\r\n",ftp->logbsize);
  565.             break;
  566.         }
  567.         ftp->typesent = ftp->type;
  568.         resp = getresp(control,200);
  569.         if(resp == -1 || resp > 299){
  570.             return 1;
  571.         }
  572.     }
  573.     if((fp = fopen(localname,mode)) == NULLFILE){
  574.         printf("Can't read %s: %s\n",localname,sys_errlist[errno]);
  575.         return 1;
  576.     }
  577.     /* Open the data connection */
  578.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  579.     listen(ftp->data,0);
  580.  
  581.     ftp->state = SENDING_STATE;
  582.  
  583.     /* Send the PORT message and wait for ack */
  584.     i = SOCKSIZE;
  585.     getsockname(ftp->data,(char *)&lsocket,&i);
  586.     sendport(control,&lsocket);
  587.     resp = getresp(control,200);
  588.     if(resp == -1 || resp > 299){
  589.         /* Error, quit */
  590.         fclose(fp);
  591.         close_s(ftp->data);
  592.         ftp->data = -1;
  593.         ftp->state = COMMAND_STATE;
  594.         return 1;
  595.     }
  596.     /* Generate the command to start the transfer and wait for ack */
  597.     usprintf(control,"STOR %s\r\n",remotename);
  598.     resp = getresp(control,100);
  599.     if(resp == -1 || resp >= 400){
  600.         /* Error, quit */
  601.         fclose(fp);
  602.         close_s(ftp->data);
  603.         ftp->data = -1;
  604.         ftp->state = COMMAND_STATE;
  605.         return 1;
  606.     }
  607.     /* Wait for the data connection to open. Otherwise the first
  608.      * block of data would go out with the SYN, and this may confuse
  609.      * some other TCPs
  610.      */
  611.     accept(ftp->data,NULLCHAR,(int *)NULL);
  612.  
  613.     startclk = Clock;
  614.  
  615.     total = sendfile(fp,ftp->data,ftp->type);
  616.     close_s(ftp->data);
  617.     ftp->data = -1;
  618.     fclose(fp);
  619.  
  620.     startclk = Clock - startclk;
  621.     if(startclk != 0)
  622.         rate = total/startclk;
  623.     else
  624.         rate = 0;
  625.     if(total != -1)
  626.         printf("Put complete: %lu bytes in %lu sec (%lu/sec)\n",
  627.          total,(startclk*MSPTICK)/1000,(rate*1000)/MSPTICK);
  628.     else
  629.         printf("Error or abort during data transfer\n");
  630.  
  631.     getresp(control,200);
  632.     ftp->state = COMMAND_STATE;
  633.     return 1;
  634. }
  635. /* Abort a GET or PUT operation in progress. Note: this will leave
  636.  * the partial file on the local or remote system
  637.  */
  638. int
  639. doabort(argc,argv,sp)
  640. int argc;
  641. char *argv[];
  642. struct session *sp;
  643. {
  644.     register struct ftpcli *ftp;
  645.  
  646.     /* Default is the current session, but it can be overridden with
  647.      * an argument.
  648.      */
  649.     if(argc > 1)
  650.         sp = sessptr(argv[1]);
  651.  
  652.     if(sp == NULLSESSION || sp->type != FTP){
  653.         printf("Not an active FTP session\n");
  654.         return 1;
  655.     }
  656.     ftp = sp->cb.ftp;
  657.  
  658.     switch(ftp->state){
  659.     case COMMAND_STATE:
  660.         printf("No active transfer\n");
  661.         return 1;
  662.     case SENDING_STATE:
  663.         /* Send a premature EOF.
  664.          * Unfortunately we can't just reset the connection
  665.          * since the remote side might end up waiting forever
  666.          * for us to send something.
  667.          */
  668.         shutdown(ftp->data,1);
  669.         break;
  670.     case RECEIVING_STATE:
  671.         /* Just blow away the receive socket */
  672.         shutdown(ftp->data,2);
  673.         break;
  674.     }
  675.     return 0;
  676. }
  677. /* send PORT message */
  678. static void
  679. sendport(s,socket)
  680. int s;
  681. struct sockaddr_in *socket;
  682. {
  683.     struct mbuf *bp;
  684.  
  685.     /* Compose and send PORT a,a,a,a,p,p message */
  686.     if((bp = alloc_mbuf(35)) == NULLBUF){    /* 5 more than worst case */
  687.         printf(Nospace);
  688.         return;
  689.     }
  690.     /* I know, this looks gross, but it works! */
  691.     sprintf(bp->data,"PORT %u,%u,%u,%u,%u,%u\r\n",
  692.         hibyte(hiword(socket->sin_addr.s_addr)),
  693.         lobyte(hiword(socket->sin_addr.s_addr)),
  694.         hibyte(loword(socket->sin_addr.s_addr)),
  695.         lobyte(loword(socket->sin_addr.s_addr)),
  696.         hibyte(socket->sin_port),
  697.         lobyte(socket->sin_port));
  698.     bp->cnt = strlen(bp->data);
  699.     send_mbuf(s,bp,0,NULLCHAR,0);
  700. }
  701.  
  702. /* Wait for, read and display response from FTP server. Return the result code.
  703.  */
  704. int
  705. getresp(s,mincode)
  706. int s;
  707. int mincode;    /* Keep reading until at least this code comes back */
  708. {
  709.     register char *line;
  710.     int rval;
  711.  
  712.     line = malloc(256);
  713.     for(;;){
  714.         /* Get line */
  715.         if(recvline(s,line,256) == -1){
  716.             rval = -1;
  717.             break;
  718.         }
  719.         rip(line);        /* Remove cr/lf */
  720.         printf("%s\n",line);    /* Display to user */
  721.  
  722.         /* Messages with dashes are continued */
  723.         if(line[3] != '-' && (rval = atoi(line)) >= mincode)
  724.             break;
  725.     }
  726.     free(line);
  727.     return rval;
  728. }
  729.  
  730. /* Issue a prompt and read a line from the user */
  731. struct mbuf *
  732. getline(sp,prompt)
  733. struct session *sp;
  734. char *prompt;
  735. {
  736.     /* If there's something already there, just grab it */
  737.     if(sp->input != NULLBUF)
  738.         return dequeue(&sp->input);
  739.  
  740.     /* Wait until we're the current session, issue prompt, and get line */
  741.     while(Current != sp || Mode != CONV_MODE)
  742.         pwait(sp);
  743.     printf("%s",prompt);
  744.     while(sp->input == NULLBUF)
  745.         pwait(&sp->input);
  746.     return dequeue(&sp->input);
  747. }
  748. /* Allocate an FTP client control block */
  749. struct ftpcli *
  750. ftp_create()
  751. {
  752.     register struct ftpcli *ftp;
  753.  
  754.     if((ftp = (struct ftpcli *)calloc(1,sizeof (struct ftpcli))) == NULLFTP)
  755.         return NULLFTP;
  756.  
  757.     ftp->state = COMMAND_STATE;
  758.         ftp->type = ASCII_TYPE;        /* Default transfer type */
  759.     ftp->typesent = ASCII_TYPE;    /* Server default is ascii */
  760.     ftp->control = ftp->data = -1;
  761.     return ftp;
  762. }
  763.